home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Speccy ClassiX 1998
/
Speccy ClassiX 98.iso
/
amiga_system
/
the_aminet
/
dev
/
gcc
/
ixemulsrc.lha
/
ixemul-41.4
/
library
/
ix_timer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-27
|
4KB
|
132 lines
/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
* Portions Copyright (C) 1994 Rafael W. Luebbert
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: ix_timer.c,v 1.3 1994/06/19 15:13:28 rluebbert Exp $
*
* $Log: ix_timer.c,v $
* Revision 1.3 1994/06/19 15:13:28 rluebbert
* *** empty log message ***
*
* Revision 1.1 1992/05/14 19:55:40 mwild
* Initial revision
*
*/
#define KERNEL
#include "ixemul.h"
#include "kprintf.h"
/*
* this is the interrupt code that distributes those itimer signals and
* collects resource information
*/
/*
* For all you "moralists" out there in Amiga land...
* This code uses exec private information about what the stack frame looks
* like inside an interrupt. However, this information is used read-only, and
* it really doesn't matter whether it will be wrong in the future, in that
* case system-time will be measured in other ways, but so what ? ;-))
*/
/* executing in ROM is considered "system" ... */
#define is_user(pc) (pc < 0xf80000 || pc > 0xffffff)
extern struct ExecBase *SysBase;
int ix_timer (char *foobar, ...) __attribute__ ((interrupt));
/*
* by specifying the function as taking varargs parameter, we force gcc
* to generate a framepointer...
*/
int
ix_timer (char *foobar, ...)
{
register struct Task *t_pass asm ("a1");
struct Task *me;
struct user *p;
/* not necessarily "me" */
struct Task *current_task = SysBase->ThisTask;
u_int current_pc;
register u_int a5 asm ("a5");
u_int sp;
struct itimerval *tim;
me = t_pass;
p = (struct user *) me->tc_TrapData;
/* find out value of sp on invocation of this function. This is easy,
* since gcc generates a
* link a5,#..
* at the beginning. So we find sp with a5+4
*/
sp = a5+4;
tim = p->u_timer;
/* The main work. Decrement the timers, and if they hit zero, generate
* the approprate signal */
/* real timer counts in real time */
if (timerisset (&tim->it_value) && !itimerdecr (tim, ITIMER_RESOLUTION))
_psignal (me, SIGALRM);
++tim;
/* virtual timer only counts, when current_task == me AND the task is
* not executing in system time. To get at the current PC, remember (or learn;-))
* that the stack in an interrupt handler looks like follows:
* 0(sp) rts into ExitIntr
* 4(sp),8(sp),12(sp),16(sp),20(sp),24(sp) -> d0/d1/a0/a1/a5/a6
* now the stuff for the correct rte instruction
* 28(sp) -> SR
* 30(sp) -> PC <- that's what we're interested in
*/
/* heuristics for 2.0.. */
current_pc = *(u_int *)(sp + 46);
if ((me == current_task) && is_user (current_pc) && timerisset(&tim->it_value) &&
!itimerdecr (tim, ITIMER_RESOLUTION))
_psignal (me, SIGVTALRM);
++tim;
/* profiling timer, runs while this process is executing, no matter
* whether in system time or not */
if ((me == current_task) &&timerisset(&tim->it_value) &&
!itimerdecr (tim, ITIMER_RESOLUTION))
_psignal (me, SIGPROF);
/* now that we're done with the timers, if this is our task executing,
* update it's rusage fields */
if (me == current_task)
{
struct timeval *tv;
tv = is_user (current_pc) ? &p->u_ru.ru_utime : &p->u_ru.ru_stime;
tv->tv_usec += ITIMER_RESOLUTION;
if (tv->tv_usec >= 1000000)
{
tv->tv_usec -= 1000000; /* - is much cheaper than % */
tv->tv_sec ++;
}
}
if (p->u_prof.pr_scale)
addupc (current_pc, &p->u_prof, 1);
return 0;
}